package edu.byu.intex2.ldap;
/*
 * Author: Conan C. Albrecht <conan@warp.byu.edu>
 *
 * This is an example of how to connect to Active Directory using JNDI
 */

import edu.byu.intex2.data.GUID;
import edu.byu.intex2.data.bo.Employee;
import edu.byu.intex2.data.bo.Salesperson;
import edu.byu.intex2.data.bo.Technician;
import edu.byu.intex2.data.dao.SalespersonDAO;
import edu.byu.intex2.data.dao.TechnicianDAO;
import java.util.*;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import java.util.regex.*;

public class LDAPController {
    /////////////////////////////////////////////
    ///   Singleton code
    private static LDAPController instance = null;

    /** Retrieves the single instance of this class */
    public static synchronized LDAPController getInstance() {
        if (instance == null) {
            instance = new LDAPController();
        }
        return instance;
    }//getInstance
    /** Error codes from LDAP (just to make things nicer) */
    public static final Map<String, String> ERROR_CODES = new HashMap<String, String>() {

        {
            put("525", "User not found");
            put("52e", "Invalid credentials");
            put("530", "Not permitted to logon at this time");
            put("532", "Password expired");
            put("533", "Account disabled");
            put("701", "Account expired");
            put("773", "User must reset password");
        }
    };

    /** The main method that connects */
    public Employee login(String username, String password) throws Exception {

        // note that this is a special format for Active Directory – it’s not the normal
        // LDAP way of doing a username.

        // Group 1-5's Intex LDAP
//        String username = "dusting";
        String domain = "madisonautogroup.info";
        String principalName = username + "@" + domain;
//        String password = "Password1"; // change this to your password
        String url = "ldap://128.187.61.44:3890";

        // set up the credential map
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, url);
        env.put(Context.SECURITY_AUTHENTICATION, "simple"); // plain text here, so not so secure
        env.put(Context.SECURITY_PRINCIPAL, principalName);
        env.put(Context.SECURITY_CREDENTIALS, password);

            // connect and log in – throws an AuthenticationException if login fails
            DirContext context = new InitialLdapContext(env, null);
            System.out.println("Connect to Active Directory succeeded");

            // locate the user’s record
            SearchControls controls = new SearchControls();
            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration<SearchResult> renum = context.search(toDC(domain), "(& (userPrincipalName=" + principalName + ")(objectClass=user))", controls);
            if (!renum.hasMore()) {
                throw new Exception("Cannot locate user information for " + username);
            }//if
            SearchResult result = renum.next();
            System.out.println("Located the user record for " + username);
            System.out.println("\t" + result.getAttributes());

            ///////////////////////////
            // Create Employee from LDAP

            // Get Employee ID from Description attribute
            Attribute id = result.getAttributes().get("description");
            Employee emp = new Employee(id.get(0).toString());

            // get the group memberships
            Attribute memberOf = result.getAttributes().get("memberOf");
            if (memberOf == null) {
                throw new Exception("This user belongs to no groups");
            }
            System.out.println("Located user groups.  Groups are:");
            for (int i = 0; i < memberOf.size(); i++) {
                Attributes atts = context.getAttributes(memberOf.get(i).toString(), new String[]{"CN"});
                Attribute group = atts.get("CN");
                System.out.println("\tGroup: " + group.get());

                // If member of salesperson group, create a salesperson
                if (group.get().equals(Employee.SALESPERSON)){
                    emp = SalespersonDAO.getInstance().read(emp.getId());
                    emp.setPosition(Employee.SALESPERSON);
                }else if (group.get().equals(Employee.TECHNICIAN)){
                    emp = TechnicianDAO.getInstance().read(emp.getId());
                    emp.setPosition(Employee.TECHNICIAN);
                }
            }

            // Assign Name
            Attribute displayName = result.getAttributes().get("displayname");
            emp.setFullName(displayName.get(0).toString());


            // Assing username and password
            emp.setUsername(username);
            emp.setPassword(password);

            // close up shop
            context.close();

            // Return our found employee
            return emp;

    }//main

    /** Simple helper method to create an LDAP-compliant DC */
    private static String toDC(String domainName) {
        StringBuilder buf = new StringBuilder();
        for (String token : domainName.split("\\.")) {
            if (token.length() == 0) {
                continue;   // defensive check
            }
            if (buf.length() > 0) {
                buf.append(",");
            }
            buf.append("DC=").append(token);
        }
        return buf.toString();
    }
}//Main